﻿/// <reference path="References/UI/FileList.ts" />
/// <reference path="Core/Enumerations.ts" />
/// <reference path="Config.ts" />
/// <reference path="Rendering/Renderer.ts" />
/// <reference path="Rendering/StarField.ts" />
/// <reference path="Rendering/ToolTip.ts" />
/// <reference path="UI/Slider.ts" />
/// <reference path="UI/DialogUI.ts" />
/// <reference path="UI/MainMenuUI.ts" />
/// <reference path="UI/ServerSelectionUI.ts" />
/// <reference path="UI/LobbyUI.ts" />
/// <reference path="UI/ReplayUI.ts" />
/// <reference path="UI/ReplayRatingUI.ts" />
/// <reference path="UI/OptionsUI.ts" />
/// <reference path="Core/FpsCounter.ts" />
/// <reference path="Core/Effect.ts" />
/// <reference path="Core/Effects.ts" />
/// <reference path="UI/Gameplay/GameUI.ts" />
/// <reference path="UI/Gameplay/CreateShipPanel.ts" />
/// <reference path="UI/Gameplay/ResearchCategoryPanel.ts" />
/// <reference path="UI/Gameplay/ShipActionsPanel.ts" />
/// <reference path="Generation/GeneratorProfile.ts" />
/// <reference path="Generation/GeneratorProfiles.ts" />
/// <reference path="Generation/Generator.ts" />
/// <reference path="Generation/NameGenerator.ts" />
/// <reference path="Core/AIHandler.ts" />
/// <reference path="Core/IPoint.ts" />
/// <reference path="Core/IZoomPoint.ts" />
/// <reference path="Core/Body.ts" />
/// <reference path="Core/BodyFacilities.ts" />
/// <reference path="Core/BodyFacilityArtillery.ts" />
/// <reference path="Core/Galaxy.ts" />
/// <reference path="Core/Location.ts" />
/// <reference path="Core/Message.ts" />
/// <reference path="Core/Artillery.ts" />
/// <reference path="Core/Missile.ts" />
/// <reference path="Core/Notices.ts" />
/// <reference path="Core/ShipPreset.ts" />
/// <reference path="Core/Ship.ts" />
/// <reference path="Core/ShipOrder.ts" />
/// <reference path="Core/Spawner.ts" />
/// <reference path="Core/StarSystem.ts" />
/// <reference path="Core/Toast.ts" />
/// <reference path="Core/Player.ts" />
/// <reference path="Core/Wreck.ts" />
/// <reference path="Core/ClickedItem.ts" />
/// <reference path="Channel.ts" />
/// <reference path="Utilities.ts" />
/// <reference path="KissRandom.ts" />
/// <reference path="GameLoop.ts" />
/// <reference path="Cheats.ts" />

module Supernova {

    export var canvas: HTMLCanvasElement;
    export var context: CanvasRenderingContext2D;
    export var aspect: number;
    export var starField;
    export var frames: number = 0;
    export var toolTipCanvas;

    export var paused: boolean = false;
    export var generatorProfile: GeneratorProfile = null;
    export var galaxy: Galaxy = null;
    export var selected: { system: StarSystem; body: Body; ships: Array<Ship> } = { system: null, body: null, ships: [] };
    export var groups: Array<Array<number>> = [];
    export var selection = null;
    export var mouseDown: boolean = false;
    export var keys = {
        up: false, down: false, left: false, right: false, control: false
    };
    export var sizes: { star: number; body: number; ship: number; pod: number; missile: number; artillery: number; orbital: number } = { star: 1, body: 1, ship: 1, pod: 1, missile: 1, artillery: 1, orbital: 1 };

    export var particles = [];
    export var activeUI: UI.ISwitchableUI = null;

    //#warning Don't keep these around; always construct
    export var gameUI: GameUI = null;
    export var mainMenuUI: MainMenuUI = null;
    export var dialogUI: DialogUI = null;
    export var serverSelectionUI: ServerSelectionUI = null;
    export var lobbyUI: LobbyUI = null;
    export var replayUI: ReplayUI = null;
    export var replayRatingUI: ReplayRatingUI = null;
    export var optionsUI: OptionsUI = null;
    export var channel: Channel = null;
    export var traitSetup: { availablePoints: number; spentPoints: number; names: Array<string> } = { availablePoints: 0, spentPoints: 0, names: [] };
    export var engineFps: FpsCounter = new FpsCounter();
    export var renderingFps: FpsCounter = new FpsCounter();

    var pendingClick: IPoint = null;

    export function initNova() {

        // Create channel
        channel = new Channel();

        // Create user interface elements
        gameUI = new GameUI();
        mainMenuUI = new MainMenuUI();
        dialogUI = new DialogUI();
        serverSelectionUI = new ServerSelectionUI();
        lobbyUI = new LobbyUI();
        replayUI = new ReplayUI();
        replayRatingUI = new ReplayRatingUI();
        optionsUI = new OptionsUI();

        // Load options
        Options.load();

        // Initialize the canvas
        canvas = <HTMLCanvasElement>document.getElementById('game-canvas');
        canvas.style.position = 'absolute';
        canvas.style.overflow = 'hidden';
        canvas.style.left = '0';
        canvas.style.top = '0';
        canvas.style.backgroundColor = 'black';
        context = canvas.getContext('2d');
        starField = new StarField();
        handleWindowResized();
        resetToMainMenu();

        // Change UI theme
        UI.COLOR_TEXT_DARK = '#232';
        UI.COLOR_TEXT_LIGHT = '#cff';

        // Assign event handlers    
        window.onresize = handleWindowResized;
        document.onmousewheel = handleMouseWheel; // IE
        document.addEventListener("DOMMouseScroll", handleMouseWheel, false); // Firefox
        canvas.onmousedown = handleMouseDown;
        canvas.onmousemove = handleMouseMove;
        canvas.onmouseup = handleMouseUp;
        canvas.onclick = handleLeftClick;
        canvas.oncontextmenu = handleRightClick;
        document.onkeydown = handleKeyDown;
        document.onkeyup = handleKeyUp;
        document.onkeypress = handleKeyPress;

        // Prevent navigation away from the page
        if (!TEST_MODE) {
            window.onbeforeunload = function () {
                return 'Are you sure you wish to exit Supernova?';
            }
        }

        // Start regular processing and rendering
        regularRendering();
        setInterval(regularProcessing, 16.6666667);

    }

    export function resetToMainMenu() {
        channel.disconnect();
        UI.swap(mainMenuUI, UI.Bounds.create(canvas));
        frames = 0;
        galaxy = null;
        selected.system = null;
        selected.body = null;
        selected.ships = [];
        groups = [];
        selection = null;
        Notices.clearToasts();
        particles = [];
    }

    export function newGame(mode: GameMode) {

        // Create a galaxy
        config = new Config();
        if (mode != GameMode.singlePlayer) {
            galaxy = new Galaxy(mode, generatorProfiles[0]);
        } else {
            galaxy = Generator.generateGalaxy(generatorProfile);
        }

        // Finish setting up synchronously if single player game
        if (mode == GameMode.singlePlayer) {
            newGameReady();
        }
    }

    export function newGameReady() {

        if (galaxy.mode != GameMode.replay) {

            // Set home system and planet details
            galaxy.home.system = findSystem((system: StarSystem) => { return system.owner == OwnerType.human; });
            galaxy.home.body = findSystemBody(galaxy.home.system, (body: Body) => { return body.population > 0; });

            // Set initial view
            galaxy.currentView = { x: galaxy.targetView.x, y: galaxy.targetView.y, zoom: MIN_ZOOM_LEVEL };
            galaxy.targetView = { x: galaxy.home.system.x, y: galaxy.home.system.y, zoom: STARTING_ZOOM_LEVEL };
        
            // Select player's home planet
            selected.body = galaxy.home.body;
        } else {

            // Some further setup is required for replay mode
            galaxy.currentView = { x: 0, y: 0, zoom: MAX_ZOOM_LEVEL };
            galaxy.targetView = { x: 0, y: 0, zoom: MIN_ZOOM_LEVEL };
            galaxy.discoverAll();
        }

        // Make victory possible
        galaxy.unlockVictory();
        
        // Recreate game UI in order to reset state of buttons (ie: research buttons)         
        gameUI = new GameUI();

        // Create effects (we do this now, after we receive slot data)
        galaxy.effects = Effects.create();

        // Activate traits
        if (galaxy.mode != GameMode.replay) {
            for (var a = 0; a < traitSetup.names.length; a++) {
                var trait = galaxy.effects.find(traitSetup.names[a]);
                galaxy.effects.activate(trait);
            }
        }

        // Switch to game UI
        UI.swap(galaxy.mode == GameMode.replay ? null : gameUI, UI.Bounds.create(canvas));
    }

    export function clearSelection() {
        selected.system = null;
        selected.body = null;
        selected.ships.length = 0;
        gameUI.shipActionsPanel.root.visible = false;
    }

    export function zoomAdd(amount: number) {
        galaxy.targetView.zoom += amount;
        if (galaxy.targetView.zoom < MIN_ZOOM_LEVEL) galaxy.targetView.zoom = MIN_ZOOM_LEVEL;
        if (galaxy.targetView.zoom > MAX_ZOOM_LEVEL) galaxy.targetView.zoom = MAX_ZOOM_LEVEL;
    }

    export function handleMouseWheel(e: MouseWheelEvent) {
        var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
        if (galaxy !== null) zoomAdd(delta);
        e.preventDefault();
        return false;
    }

    export function handleMouseDown(e: MouseEvent) {
        var control = UI.getControlByPosition(UI.root, e.pageX, e.pageY);
        if (control !== null) {
            UI.handleMouseDown(e.pageX, e.pageY);
        } else if (e.button == 0 && galaxy !== null) {
            mouseDown = true;
            selection = { x1: e.pageX, y1: e.pageY, x2: e.pageX, y2: e.pageY };
        }
    }

    export function handleMouseMove(e: MouseEvent) {
        UI.handleMouseMove(e.pageX, e.pageY);
        var control = UI.getControlByPosition(UI.root, e.pageX, e.pageY);
        if (control === null) {
            toolTipCanvas = null;
        }
        if (selection !== null && galaxy !== null) {
            if (mouseDown) {
                var width = Math.abs(e.pageX - selection.x1);
                var height = Math.abs(e.pageY - selection.y1);
                if (width >= 12 || height >= 12) {
                    selection.x2 = e.pageX;
                    selection.y2 = e.pageY;
                } else {
                    selection.x2 = selection.x1;
                    selection.y2 = selection.y1;
                }
            } else {
                selection = null;
            }
        }
    }

    export function handleMouseUp(e: MouseEvent) {
        var control = UI.getControlByPosition(UI.root, e.pageX, e.pageY);
        if (control !== null) {
            UI.handleMouseUp(e.pageX, e.pageY);
        } else if (e.button == 0 && galaxy !== null) {

            // Handle box selection
            if (selection !== null && (selection.x1 != selection.x2 || selection.y1 != selection.y2)) {
                handleBoxSelection();
            } else {

                // Change the selection based on what the user clicked
                var entity = getEntityAt(e.pageX, e.pageY);
                if (entity.emptySpace === false) {
                    clearSelection();
                    selected.system = entity.system;
                    selected.body = entity.body;

                    // Center around a star if one has been clicked
                    if (entity.system !== null) {
                        galaxy.targetView.x = entity.system.x;
                        galaxy.targetView.y = entity.system.y;
                    }

                    // Did the user select a ship?
                    if (entity.ship !== null) {
                        if (e.ctrlKey && entity.ship.owner == OwnerType.human) {
                            for (var s in galaxy.ships) {
                                var otherShip = galaxy.ships[s];
                                if (otherShip.owner == OwnerType.human && otherShip.preset.equals(entity.ship.preset)) {
                                    selected.ships.push(otherShip);
                                }
                            }
                        } else {
                            selected.ships.push(entity.ship);
                        }
                    }
                    gameUI.hidePanels();
                    gameUI.shipActionsPanel.root.visible = selected.ships.length > 0;
                }
            }

            // Clear selection
            selection = null;
            mouseDown = false;
        } else if (e.button == 1) {

            // Center around the clicked point
            var targetLocation = screenToWorld(e.pageX, e.pageY);
            galaxy.targetView.x = targetLocation.x;
            galaxy.targetView.y = targetLocation.y;
        }
    }

    export function handleLeftClick(e: MouseEvent) {
        var control = UI.getControlByPosition(UI.root, e.pageX, e.pageY);
        if (control !== null) {
            UI.handleClick(e.pageX, e.pageY);
        } else if (galaxy !== null) {
            pendingClick = { x: e.pageX, y: e.pageY };
        }
    }

    export function handleRightClick(e: MouseEvent) {
        var control = UI.getControlByPosition(UI.root, e.pageX, e.pageY);
        if (control !== null) {
            UI.handleClick(e.pageX, e.pageY);
        } else if (galaxy !== null && galaxy.mode != GameMode.replay) {

            // Create an order for all of the selected ships
            if (selected.ships.length > 0) {
                var entity = getEntityAt(e.pageX, e.pageY);
                var anchorLocation = null;
                for (var shipKey in selected.ships) {
                    var ship = selected.ships[shipKey];
                    if (ship.owner == OwnerType.human) {

                        // Create the order
                        var clickedSomethingValid = true;
                        var order = ShipOrder.create(ShipOrderType.move);
                        order.targetLocation = new Location();
                        if (entity.emptySpace === true) {
                            var location = screenToWorld(e.pageX, e.pageY);
                            if (anchorLocation === null) anchorLocation = { x: ship.currentLocation.x, y: ship.currentLocation.y };
                            var relativeX = ship.currentLocation.x - anchorLocation.x;
                            var relativeY = ship.currentLocation.y - anchorLocation.y;
                            if (ship.formation) {
                                order.targetLocation.setXY(location.x + relativeX, location.y + relativeY);
                            } else {
                                order.targetLocation.setXY(location.x, location.y);
                            }
                        } else if (entity.system !== null) {
                            order.targetLocation.setSystem(entity.system);
                        } else if (entity.body !== null) {
                            order.targetLocation.setBody(entity.body);
                        } else if (entity.ship !== null) {
                            if (entity.ship != ship) {
                                order.targetLocation.setShip(entity.ship);
                            }
                        } else {
                            clickedSomethingValid = false;
                        }

                        // Add to the orders list
                        if (clickedSomethingValid) {
                            if (!e.ctrlKey) {
                                ship.clearOrders();
                            }
                            ship.orders.push(order);
                        }
                    }
                }
            }
        }
        return false;
    }

    export function handleKeyDown(e: KeyboardEvent) {
        var handled = UI.handleKeyDown(e);
        var key = UI.getKey(e).toLowerCase();
        if (!handled) {
            if (activeUI == mainMenuUI) {
                if (key == 'm') mainMenuUI.handleMultiplayerButtonClick(null, null);
            } else if (activeUI == lobbyUI) {
                if (key == 'j' && TEST_MODE) lobbyUI.handleJoinButtonClick(null, null);
                if (key == 'r' && TEST_MODE) lobbyUI.handleReadyButtonClick(null, null);
            }
        }
        if (!handled && galaxy !== null) {
            if (key == 'control') keys.control = true;

            // Zoom and pan
            if (key == 'arrowleft') keys.left = true;
            if (key == 'arrowright') keys.right = true;
            if (key == 'arrowup') keys.up = true;
            if (key == 'arrowdown') keys.down = true;
            if (key == 'pageup') zoomAdd(1);
            if (key == 'pagedown') zoomAdd(-1);

            // (Mostly) centering of view
            if (key == 'c' && !gameUI.createShipPanel.root.visible) {
                if (selected.ships.length > 0) {
                    if (galaxy.mode != GameMode.replay && (e.ctrlKey || findSelectedShips(function (s) { return s.calculated.canColonise; }).length > 0)) {
                        galaxy.coloniseAction(e.ctrlKey);
                    } else {
                        galaxy.targetView.zoom = galaxy.targetView.zoom == STARTING_ZOOM_LEVEL ? MIN_ZOOM_LEVEL : STARTING_ZOOM_LEVEL;
                        galaxy.targetView.x = selected.ships[0].currentLocation.x;
                        galaxy.targetView.y = selected.ships[0].currentLocation.y;
                    }
                } else if (selected.body !== null) {
                    galaxy.targetView.zoom = galaxy.targetView.zoom == STARTING_ZOOM_LEVEL ? MIN_ZOOM_LEVEL : STARTING_ZOOM_LEVEL;
                    galaxy.targetView.x = selected.body.x;
                    galaxy.targetView.y = selected.body.y;
                } else if (selected.system !== null) {
                    galaxy.targetView.zoom = galaxy.targetView.zoom == STARTING_ZOOM_LEVEL ? MIN_ZOOM_LEVEL : STARTING_ZOOM_LEVEL;
                    galaxy.targetView.x = selected.system.x;
                    galaxy.targetView.y = selected.system.y;
                }
            }

            // Nothing else is allowed if the game mode is replay
            if (galaxy.mode == GameMode.replay) return;

            // Groups
            var numberKey = String.fromCharCode(e.keyCode);
            if (numberKey >= '1' && numberKey <= '9') {
                if (e.ctrlKey || e.shiftKey) {
                    if (e.ctrlKey || groups[numberKey] === undefined) {
                        groups[numberKey] = [];
                    }
                    for (var shipKey in selected.ships) {
                        var ship = selected.ships[shipKey];
                        if (ship.owner == OwnerType.human) {
                            groups[numberKey].push(ship.code);
                        }
                    }
                }
                if (!e.ctrlKey && (e.shiftKey || groups[numberKey] !== undefined)) {
                    clearSelection();
                    gameUI.hidePanels();
                    var group = groups[numberKey];
                    for (var i = 0; i < group.length; i++) {
                        var ship = findShipByCode(group[i]);
                        if (ship !== null && ship !== undefined) {
                            selected.ships.push(ship);
                        }
                    }
                    gameUI.shipActionsPanel.root.visible = selected.ships.length > 0;
                }
            }

            if (key == 'q' && gameUI.newFacilityButton.enabled) gameUI.handleNewFacilityButtonClicked(null, null);
            if (key == 'w' && gameUI.newScienceButton.enabled) gameUI.handleNewScienceButtonClicked(null, null);
            if (key == 'e' && gameUI.newShipButton.enabled) gameUI.handleNewShipButtonClicked(null, null);
            if (key == 's') galaxy.stopAction();
            if (key == 't') galaxy.terraformAction(e.ctrlKey);
            if (key == 'i') galaxy.bombardAction(e.ctrlKey);
            if (key == 'n') galaxy.exploreAction(e.ctrlKey);
            if (key == 'r') galaxy.repairAction(e.ctrlKey);
            if (key == '-') galaxy.disbandAction(e.ctrlKey);
            if (key == 'pause' && gameUI.pauseButton.enabled) gameUI.handlePauseButtonClicked(null, null);

            // Shortcut keys for create ship panel
            if (gameUI.createShipPanel.root.visible) {
                if (key == 'delete') gameUI.createShipPanel.handleResetShipButtonClicked(null, null);
                if (key == 'c') gameUI.createShipPanel.handleCreateShipButtonClicked(null, null);
                if (key == 's') gameUI.createShipPanel.handleSavePresetButtonClicked(null, null);
                if (key >= '0' && key <= '9') {
                    gameUI.createShipPanel.newShipQuantityTextBox.text = key;
                    if (key == '0') gameUI.createShipPanel.newShipQuantityTextBox.text = '10';
                    gameUI.createShipPanel.handleCreateShipButtonClicked(null, null);
                }
            }

            // Selection of closest ship yard, or creation of ship if a ship yard's planet has been selected
            if (key == 'y') {
                if (gameUI.newShipButton.enabled) {
                    gameUI.createShipPanel.handleSliderValueChanged(null, null);
                    gameUI.createShipPanel.handleCreateShipButtonClicked(null, null);
                } else {
                    var searchFunction = findBodies((body: Body) => { return body.system.owner == OwnerType.human && body.facilities.shipyard; });
                    var body = findClosestThing<Body>(searchFunction, galaxy.currentView.x, galaxy.currentView.y);
                    if (body !== null) {
                        clearSelection();
                        selected.body = body;
                    }
                }
            }

            // Game speed
            if (!channel.online && (key == '[' || key == ']')) {
                if (key == '[' && galaxy.speedMultiplier > 0.125) {
                    galaxy.speedMultiplier = galaxy.speedMultiplier / 2;
                }
                if (key == ']' && galaxy.speedMultiplier < 16) {
                    galaxy.speedMultiplier = galaxy.speedMultiplier * 2;
                }
                Notices.addMessage(MessageType.information, 'Game speed multiplier set to ' + galaxy.speedMultiplier + '.');
            }

            // Buildings
            if (key == 'f1' || key == 'p' && gameUI.buildCommsButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildCommsButton, null);
            if (key == 'f2' && gameUI.buildScienceButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildScienceButton, null);
            if (key == 'f3' && gameUI.buildShipyardButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildShipyardButton, null);
            if (key == 'f4' && gameUI.buildScannerButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildScannerButton, null);
            if (key == 'f5' && gameUI.buildMiningButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildMiningButton, null);
            if (key == 'f6' || key == 'o' && gameUI.buildOrbitalButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildOrbitalButton, null);
            if (key == 'f7' && gameUI.buildArtilleryButton.enabled) gameUI.handleBuildButtonClicked(gameUI.buildArtilleryButton, null);

            if (key == 'd' && gameUI.createShipPanel.draftButton.visible && gameUI.createShipPanel.draftButton.enabled) gameUI.createShipPanel.handleDraftButtonClicked(null, null);
            if (key == 'f') {
                var mode = false;
                var first = true;
                for (var j in selected.ships) {
                    var ship = selected.ships[j];
                    if (first) {
                        if (ship.owner != OwnerType.human) break;
                        mode = ship.formation;
                        first = false;
                    }
                    ship.formation = !mode;
                }
            }
            if (key == 'x' && selected.ships.length > 0) {
                fanShips();
            }
        }
        e.preventDefault();
    }

    export function handleKeyUp(e: KeyboardEvent) {
        var key = UI.getKey(e);
        if (!UI.handleKeyUp(e)) {
            if (key == 'Control') keys.control = false;
            if (key == 'ArrowLeft') keys.left = false;
            if (key == 'ArrowRight') keys.right = false;
            if (key == 'ArrowUp') keys.up = false;
            if (key == 'ArrowDown') keys.down = false;
        }
        e.preventDefault();
    }

    export function handleKeyPress(e: KeyboardEvent) {
        UI.handleKeyPress(e);
        e.preventDefault();
    }

    export function handleBoxSelection() {
        clearSelection();
        gameUI.hidePanels();
        gameUI.shipActionsPanel.root.visible = false;
        var box = convertToBox(selection.x1, selection.y1, selection.x2, selection.y2);
        var topLeft = screenToWorld(box.left, box.top);
        var bottomRight = screenToWorld(box.right, box.bottom);

        // Find human ships that fit inside the selection
        var selectedShips = [];
        for (var shipKey in galaxy.ships) {
            var ship = galaxy.ships[shipKey];
            if (ship.owner == OwnerType.human && ship.currentLocation.x >= topLeft.x && ship.currentLocation.y >= topLeft.y && ship.currentLocation.x <= bottomRight.x && ship.currentLocation.y <= bottomRight.y) {
                selectedShips.push(ship);
                gameUI.shipActionsPanel.root.visible = true;
            }
        }

        // If no human ships selected then try selecting enemy ships
        if (selectedShips.length == 0) {
            var selectedShipOwner = OwnerType.none;
            for (var shipKey in galaxy.ships) {
                var ship = galaxy.ships[shipKey];
                var sameOwner = selectedShipOwner == OwnerType.none || selectedShipOwner == ship.owner;
                var visible = ship.visible || galaxy.mode == GameMode.replay;
                if (sameOwner && visible && ship.currentLocation.x >= topLeft.x && ship.currentLocation.y >= topLeft.y && ship.currentLocation.x <= bottomRight.x && ship.currentLocation.y <= bottomRight.y) {
                    selectedShips.push(ship);
                    selectedShipOwner = ship.owner;
                }
            }
        }
        selected.ships = selectedShips;

        // If no ships were found, perhaps the user was trying to select a body?
        if (selected.ships.length == 0) {
            for (var i = 0; i < galaxy.starSystems.length; i++) {
                var system = galaxy.starSystems[i];
                if (system.discovered) {
                    for (var j = 1; j < system.bodies.length; j++) {
                        var body = system.bodies[j];
                        if (body.x >= topLeft.x && body.y >= topLeft.y && body.x <= bottomRight.x && body.y <= bottomRight.y) {
                            selected.body = body;
                        }
                    }
                }
            }
        }

        // If no bodies were found, perhaps the user was trying to select a system?
        if (selected.ships.length == 0 && selected.body === null) {
            for (var i = 0; i < galaxy.starSystems.length; i++) {
                var system = galaxy.starSystems[i];
                if (system.x >= topLeft.x && system.y >= topLeft.y && system.x <= bottomRight.x && system.y <= bottomRight.y) {
                    selected.system = system;
                }
            }
        }
    }

    export function updateEnabledButtons() {

        // Ship control buttons
        var panel = gameUI.shipActionsPanel;
        panel.stopButton.enabled = false;
        panel.terraformButton.enabled = false;
        panel.coloniseButton.enabled = false;
        panel.bombardButton.enabled = false;
        panel.exploreButton.enabled = false;
        panel.repairButton.enabled = false;
        panel.disbandButton.enabled = false;
        for (var shipKey in selected.ships) {
            var ship = selected.ships[shipKey];
            if (ship.owner != OwnerType.human) break;
            if (ship.calculated.canStop) panel.stopButton.enabled = true;
            if (keys.control || ship.calculated.canTerraform) panel.terraformButton.enabled = gameUI.createShipPanel.terraformingSlider.enabledValues > 0;
            if (keys.control || ship.calculated.canColonise) panel.coloniseButton.enabled = gameUI.createShipPanel.populationSlider.enabledValues > 0;
            if (keys.control || ship.calculated.canBombard) panel.bombardButton.enabled = gameUI.createShipPanel.bombardSlider.enabledValues > 0;
            if (keys.control || ship.calculated.canExplore) panel.exploreButton.enabled = galaxy.research.actions.explore == true;
            if (keys.control || ship.calculated.canRepair) panel.repairButton.enabled = galaxy.research.actions.repair == true;
            if (keys.control || ship.calculated.canDisband) panel.disbandButton.enabled = true;
        }

        // Facility buttons
        var selectedSystem = selected.body === null ? null : selected.body.system;
        var canBuildFacility = selected.body !== null && selectedSystem.owner == OwnerType.human && selected.body.population > 0;
        gameUI.newFacilityButton.enabled = canBuildFacility;
        gameUI.buildScannerButton.enabled = canBuildFacility && galaxy.research.facilities.scanner === true && selected.body.facilities.scanner === false;
        gameUI.buildScienceButton.enabled = canBuildFacility && selected.body.facilities.science === false;
        gameUI.buildShipyardButton.enabled = canBuildFacility && selected.body.facilities.shipyard === false;
        gameUI.buildCommsButton.enabled = canBuildFacility && galaxy.research.facilities.comms === true && selected.body.facilities.comms === false;
        gameUI.buildMiningButton.enabled = canBuildFacility && galaxy.research.facilities.mining === true && selected.body.facilities.mine === false && selected.body.gold > 0;
        gameUI.buildOrbitalButton.enabled = canBuildFacility && galaxy.research.facilities.orbital === true && selected.body.facilities.orbitals < MAX_ORBITALS;
        gameUI.buildArtilleryButton.enabled = canBuildFacility && galaxy.research.artillery.planetary.enabled === true && selected.body.facilities.artillery === null;

        // Shipyard buttons
        gameUI.createShipPanel.draftButton.enabled = galaxy.research.actions.draft && selected.body !== null && selectedSystem.owner == OwnerType.human && selected.body.facilities.shipyard && selected.body.population > config.draftCost;
    }

    export function regularRendering() {
        window.requestAnimationFrame(regularRendering);
        var clicked = drawScene(pendingClick);
        pendingClick = null;
        if (clicked.ship !== null) {
            selected.ships = [clicked.ship];
        }
        UI.render(context);
        if (Options.showToolTips && toolTipCanvas != null) {
            if (UI.mouse.x + 8 + toolTipCanvas.width > canvas.width) {
                context.drawImage(toolTipCanvas, UI.mouse.x - toolTipCanvas.width - 8, UI.mouse.y + 8);
            } else {
                context.drawImage(toolTipCanvas, UI.mouse.x + 8, UI.mouse.y + 8);
            }
        }
        renderingFps.endFrame();
    };

    export function fanShips() {
        for (var shipKey in selected.ships) {
            var ship = selected.ships[shipKey];
            if (ship.owner == OwnerType.human && ship.orders.length == 0) {
                var point = randomPointInCircle(galaxy.profile.systems.maxPlanetDistance * 0.5);
                var order = ShipOrder.createWithLocation(ShipOrderType.move, ship.currentLocation.x + point.x, ship.currentLocation.y + point.y);
                ship.setSingleOrder(order);
            }
        }
    }

}